#include "CRealNotify.h"
#include <QDateTime>
#include <QThread>

map<int, CRealNotify*> CRealNotify::cls_mapInstance;

thread*	CRealNotify::s_pThread = nullptr;

CRealNotify::CRealNotify(int nKeyValue)
{
	_nModule = nKeyValue;
}
CRealNotify::~CRealNotify()
{
}
void CRealNotify::AddNotifyInfo(const NOTIFYNODE& notify)
{
    lock_guard<mutex> lock(m_locker);

    qint64 ncuticks = QDateTime::currentSecsSinceEpoch();
    if (notify._notifytype != CLCOMNOTIFY_JUST_NOTIFY)
    {
        auto itticks = _mapTicks.find(notify._notifytype);

        if (itticks != _mapTicks.end())
        {
            if (5 > abs(itticks->second - ncuticks))
            {
                return;
            }
        }
    }

    PNOTIFYNODE pnode = new NOTIFYNODE;

    pnode->Clone(notify);

    auto it = _mapError.find(notify._notifytype);
    if (it == _mapError.end())
    {
        _mapError[notify._notifytype].push_back(pnode);
    }
    else
    {
        auto itend = it->second.end();

        if (CLCOMNOTIFY_JUST_NOTIFY != notify._notifytype)
        {
            if (it->second.size() > 0)
            {
                --itend;
                for (int i = 0; i < 3; ++i)
                {
                    if (itend != it->second.end())
                    {
                        if ((*itend)->_notifytype == notify._notifytype)
                        {
                            return;
                        }
                    }
                    if (itend == it->second.begin())
                    {
                        break;
                    }
                    --itend;
                }
            }

            if (it->second.size() >= CLCOMNOTIFY_MAX_COUNT)
            {
                it->second.pop_front();
            }
        }
        it->second.push_back(pnode);
    }
}
void CRealNotify::AddNotifyInfo(const char* info, int datalen, int nType)
{
    NOTIFYNODE node;
    node._notifytype = nType;

    node._datalen = 0;

    node._pData = nullptr;

    if (datalen >= CLCOMNOTIFY_MAXLEN_EXINFO)
    {
        node._datalen = datalen;
        node._pData = (void*)info;
    }
    else
    {
        memcpy((void*)node._descriptInfo, (void*)info, node._datalen);
    }
    AddNotifyInfo(node);
}

void  ThreadPostNotify(void* pra)
{
    Q_UNUSED(pra);
	while (true)
	{
        map<int, CRealNotify*>::iterator itinstance =
                CRealNotify::cls_mapInstance.begin();

        for (;
             itinstance != CRealNotify::cls_mapInstance.end();
             ++itinstance)
		{
            itinstance->second->m_locker.lock();

            std::map<int, std::list<PNOTIFYNODE>>::iterator it =
                    itinstance->second->_mapError.begin();
            for (;
                 it != itinstance->second->_mapError.end();
                 ++it)
			{
                std::list<PNOTIFYNODE>::iterator itl =
                        it->second.begin();
				for (; itl != it->second.end(); ++itl)
                {
					if (itinstance->second->_initInfo._pCallback)
					{
                        itinstance->second->_initInfo._pCallback(*itl);
					}

                    QThread::msleep(100);
				}
				it->second.clear();
			}
            itinstance->second->m_locker.unlock();
		}
        QThread::msleep(SEND_GAP);
	}
}
void CRealNotify::InitMsgNotify(
        int nModule,
        NOTIFYINFO& initInfo)
{
    map<int, CRealNotify*>::iterator it =
            CRealNotify::cls_mapInstance.find(nModule);
    if (it == CRealNotify::cls_mapInstance.end())
	{
        CRealNotify* pnew = new CRealNotify(nModule);

		cls_mapInstance[nModule] = pnew;

        memcpy(
                    (void*)&pnew->_initInfo,
                    (void*)&initInfo,
                    sizeof(NOTIFYINFO));
        s_pThread = new thread(ThreadPostNotify, nullptr);
	}
	else
	{
		it->second->_nModule = nModule;
		memcpy((void*)&it->second->_initInfo, (void*)&initInfo, sizeof(NOTIFYINFO));

        s_pThread = new thread(ThreadPostNotify, nullptr);
	}
}

CRealNotify* CRealNotify::GetErrorInstance(int nKey)
{
    map<int, CRealNotify*>::iterator it = CRealNotify::cls_mapInstance.find(nKey);
    if (it == CRealNotify::cls_mapInstance.end())
	{
        CRealNotify* pnew = new CRealNotify(nKey);

		cls_mapInstance[nKey] = pnew;
		return pnew;
	}
	return it->second;
}
